SIGNIN

Ez_Caesar


题目描述:小蓝鲨看你们牢底坐穿决定送你们一点分。


下载附件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def variant_caesar_encrypt(text):
encrypted = ""
shift = 2
for char in text:
if char.isalpha():
if char.isupper():
base = ord('A')
new_char = chr((ord(char) - base + shift) % 26 + base)
else:
base = ord('a')
new_char = chr((ord(char) - base + shift) % 26 + base)
encrypted += new_char
shift += 3
else:
encrypted += char
return encrypted

# KXKET{Tubsdx_re_hg_zytc_hxq_vnjma}

是简单的凯撒编码,直接在原来基础上编写decrypt函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def variant_caesar_decrypt(ciphertext):
decrypted = ""
shift = 2
for char in ciphertext:
if char.isalpha():
if char.isupper():
base = ord('A')
original_char = chr((ord(char) - base - shift) % 26 + base)
else:
base = ord('a')
original_char = chr((ord(char) - base - shift) % 26 + base)
decrypted += original_char
shift += 3
else:
decrypted += char
return decrypted

ciphertext = "KXKET{Tubsdx_re_hg_zytc_hxq_vnjma}"
print(variant_caesar_decrypt(ciphertext))

#flag:ISCTF{Caesar_is_so_easy_and_funny}

小蓝鲨的RC4系统


题目描述:送都送了,再给一个。


下载附件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import hashlib

class StreamCipher:
def __init__(self, key):

self.S = list(range(256))
self.i = 0
self.j = 0

j = 0
key_bytes = self._key_to_bytes(key)
for i in range(256):
j = (j + self.S[i] + key_bytes[i % len(key_bytes)]) % 256
self.S[i], self.S[j] = self.S[j], self.S[i]

def _key_to_bytes(self, key):

if isinstance(key, str):
return hashlib.sha256(key.encode()).digest()
elif isinstance(key, bytes):
return hashlib.sha256(key).digest()

def _prga(self):

self.i = (self.i + 1) % 256
self.j = (self.j + self.S[self.i]) % 256
self.S[self.i], self.S[self.j] = self.S[self.j], self.S[self.i]
K = self.S[(self.S[self.i] + self.S[self.j]) % 256]
return K

def crypt(self, data):

if isinstance(data, str):
data = data.encode('utf-8')

result = bytearray()
for byte in data:
key_byte = self._prga()
result.append(byte ^ key_byte)

return bytes(result)

def encrypt_string(text, key):

cipher = StreamCipher(key)
encrypted = cipher.crypt(text)
return encrypted.hex()

#ISCTF2025
#ba19a7116763ba8ba1c236c6bdc30187dcc8afb28c8fa5f266763880b74f5fff915613718f4d19c3baf4bbe24bd57303ce103d

得到是RC4流密码加密,

RC4的加密和解密用的为同一个函数(异或操作为自反的),所以解密只需把密文从十六进制转成字节,再调用crypt

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import hashlib

class StreamCipher:
def __init__(self, key):
self.S = list(range(256))
self.i = 0
self.j = 0
j = 0
key_bytes = self._key_to_bytes(key)
for i in range(256):
j = (j + self.S[i] + key_bytes[i % len(key_bytes)]) % 256
self.S[i], self.S[j] = self.S[j], self.S[i]

def _key_to_bytes(self, key):
if isinstance(key, str):
return hashlib.sha256(key.encode()).digest()
elif isinstance(key, bytes):
return hashlib.sha256(key).digest()

def _prga(self):
self.i = (self.i + 1) % 256
self.j = (self.j + self.S[self.i]) % 256
self.S[self.i], self.S[self.j] = self.S[self.j], self.S[self.i]
K = self.S[(self.S[self.i] + self.S[self.j]) % 256]
return K

def crypt(self, data):
if isinstance(data, str):
data = data.encode('utf-8')
result = bytearray()
for byte in data:
key_byte = self._prga()
result.append(byte ^ key_byte)
return bytes(result)

def decrypt_hex(hex_data, key):
ciphertext_bytes = bytes.fromhex(hex_data)
cipher = StreamCipher(key)
decrypted_bytes = cipher.crypt(ciphertext_bytes)
return decrypted_bytes.decode('utf-8')

if __name__ == "__main__":
hex_data = "ba19a7116763ba8ba1c236c6bdc30187dcc8afb28c8fa5f266763880b74f5fff915613718f4d19c3baf4bbe24bd57303ce103d"
key = "ISCTF2025"
print(decrypt_hex(hex_data, key))

#flag: ISCTF{Welcome_to_ISCTF_&_this_is_a_secret_with_RC4}

MISC

Guess!


题目描述:这是一个经典的猜数字,开始你的数字解密之旅吧!


下载附件,是pyinstaller处理后的MiscNumberChallenge.exe,用unpack.py解包后得到extracted目录

找到misc_challenge.pyc文件,在 https://pylingual.io/ 反编译.pyc文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import random
import time
import sys
import base64

def decode_flag(encoded_flag):
"""解码隐藏的Flag"""
try:
decoded = base64.b64decode(encoded_flag).decode('utf-8')
decoded = base64.b64decode(decoded).decode('utf-8')
return decoded
except:
return 'Flag解码错误'

def main():
secret_number = random.randint(1, 100)
max_attempts = 10
encoded_flag = 'SVNDVEZ7OXVlU3NfdGhFX0BuJHdlUn0='
encoded_flag = base64.b64encode(encoded_flag.encode()).decode()
print('==================================================')
print('欢迎参加Misc猜数字挑战!')
print(f'系统已生成1-100之间的秘密数字,你有{max_attempts}次机会')
print('猜对数字即可获得Flag!')
print('==================================================')
for attempt in range(max_attempts):
remaining = max_attempts - attempt
print(f'\n[剩余机会: {remaining}]')
while True:
try:
guess = int(input('请输入你的猜测 (1-100): '))
if 1 <= guess <= 100:
break
print('请输入1-100之间的整数!')
except:
print('无效输入!请输入整数。')
if guess < secret_number:
print(f'{guess} → 太小了,继续努力!')
elif guess > secret_number:
print(f'{guess} → 太大了,往小试试!')
else:
print('==================================================')
print(f'★ 恭喜!你猜对了!数字就是 {secret_number}')
print('★ 恭喜获得Flag:')
flag = decode_flag(encoded_flag)
print(f'★ {flag}')
print('==================================================')
print('程序将在10秒后关闭...')
time.sleep(10)
return
else:
print('\n==================================================')
print('⚠️ 挑战失败!')
print(f'⚠️ 正确答案是: {secret_number}')
print('⚠️ 请重新运行程序再次尝试!')
print('==================================================')
print('程序将在10秒后关闭...')
time.sleep(10)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print('\n\n程序已中断。')
sys.exit()

容易得到,flag编码为base64,解码即得flag:ISCTF{9ueSs_thE_@n$weR}

REVERSE

ezzz_math


题目描述:来解方程吧


IDA中打开,可疑点_main函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
int i; // [esp+4h] [ebp-6Ch]
char Str[100]; // [esp+8h] [ebp-68h] BYREF

sub_403B50(aPleaseInputYou);
sub_403B50(aTryToUseZ3Solv);
sub_403B90("%80s", Str);
if ( strlen(Str) == 23 )
{
for ( i = 0; i < 23; ++i )
Str[i] ^= 0xCu;
if ( sub_401000(Str) )
puts(aRight);
else
puts(aWrong);
}
else
{
puts(Buffer);
}
return 0;
}

逻辑就是输入23字节字符串,用0xC(12)异或,最后将异或完的数组传给sub_401000验证。

所以,我们看向sub_401000函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
BOOL __cdecl sub_401000(char *a1)
{
return 94 * a1[22]
+ 74 * a1[21]
+ 70 * a1[19]
+ 12 * a1[18]
+ 20 * a1[16]
+ 62 * a1[12]
+ 82 * a1[10]
+ 7 * a1[7]
+ 63 * a1[6]
+ 18 * a1[5]
+ 58 * a1[4]
+ 94 * a1[2]
+ 77 * *a1
- 43 * a1[1]
- 37 * a1[3]
- 97 * a1[8]
- 23 * a1[9]
- 86 * a1[11]
- 6 * a1[13]
- 5 * a1[14]
- 79 * a1[15]
- 63 * a1[17]
- 93 * a1[20] == 20156
&& 87 * a1[22]
+ 75 * a1[21]
+ 73 * a1[15]
+ 67 * a1[14]
+ 30 * a1[13]
+ (a1[11] << 6)
+ 35 * a1[9]
+ 91 * a1[7]
+ 91 * a1[5]
+ 34 * a1[3]
+ 74 * *a1
- 89 * a1[1]
- 72 * a1[2]
- 76 * a1[4]
- 32 * a1[6]
- 97 * a1[8]
- 39 * a1[10]
- 23 * a1[12]
+ 8 * a1[16]
- 98 * a1[17]
- 4 * a1[18]
- 80 * a1[19]
- 83 * a1[20] == 7183
&& 51 * a1[21]
+ 22 * a1[20]
+ 15 * a1[19]
+ 51 * a1[17]
+ 96 * a1[12]
+ 34 * a1[7]
+ 77 * a1[5]
+ 59 * a1[2]
+ 89 * a1[1]
+ 92 * *a1
- 85 * a1[3]
- 50 * a1[4]
- 51 * a1[6]
- 75 * a1[8]
- 40 * a1[10]
- 4 * a1[11]
- 74 * a1[13]
- 98 * a1[14]
- 23 * a1[15]
- 14 * a1[16]
- 92 * a1[18]
- 7 * a1[22] == -7388
&& 61 * a1[22]
+ 72 * a1[21]
+ 28 * a1[20]
+ 55 * a1[18]
+ 20 * a1[17]
+ 13 * a1[14]
+ 51 * a1[13]
+ 69 * a1[12]
+ 10 * a1[11]
+ 95 * a1[10]
+ 43 * a1[9]
+ 53 * a1[8]
+ 76 * a1[7]
+ 25 * a1[6]
+ 9 * a1[5]
+ 10 * a1[4]
+ 98 * a1[1]
+ 70 * *a1
- 22 * a1[2]
+ 2 * a1[3]
- 49 * a1[15]
+ 4 * a1[16]
- 77 * a1[19] == 69057
&& 7 * a1[22]
+ 21 * a1[16]
+ 22 * a1[13]
+ 55 * a1[9]
+ 66 * a1[8]
+ 78 * a1[5]
+ 10 * a1[3]
+ 80 * a1[1]
+ 65 * *a1
- 20 * a1[2]
- 53 * a1[4]
- 98 * a1[6]
+ 8 * a1[7]
- 78 * a1[10]
- 94 * a1[11]
- 93 * a1[12]
- 18 * a1[14]
- 48 * a1[15]
- 9 * a1[17]
- 73 * a1[18]
- 59 * a1[19]
- 68 * a1[20]
- 74 * a1[21] == -31438
&& 33 * a1[19]
+ 78 * a1[15]
+ 66 * a1[10]
+ 3 * a1[9]
+ 43 * a1[4]
+ 24 * a1[3]
+ 3 * a1[2]
+ 27 * *a1
- 18 * a1[1]
- 46 * a1[5]
- 18 * a1[6]
- a1[7]
- 33 * a1[8]
- 50 * a1[11]
- 23 * a1[12]
- 37 * a1[13]
- 45 * a1[14]
+ 2 * a1[16]
- a1[17]
- 60 * a1[18]
- 87 * a1[20]
- 72 * a1[21]
- 6 * a1[22] == -26121
&& 31 * a1[20]
+ 80 * a1[18]
+ 34 * a1[17]
+ 34 * a1[15]
+ 38 * a1[14]
+ 53 * a1[13]
+ 35 * a1[12]
+ 82 * a1[9]
+ 27 * a1[8]
+ 80 * a1[7]
+ 46 * a1[6]
+ 18 * a1[4]
+ 5 * a1[1]
+ 98 * *a1
- 12 * a1[2]
- 9 * a1[3]
- 57 * a1[5]
- 46 * a1[10]
- 31 * a1[11]
- 68 * a1[16]
- 94 * a1[19]
- 93 * a1[21]
- 15 * a1[22] == 26005
&& 81 * a1[21]
+ 40 * a1[20]
+ 34 * a1[19]
+ 94 * a1[18]
+ 98 * a1[17]
+ 11 * a1[14]
+ 63 * a1[13]
+ 95 * a1[12]
+ 43 * a1[11]
+ 99 * a1[10]
+ 29 * a1[9]
+ 81 * a1[6]
+ 72 * a1[5]
+ 54 * a1[3]
+ 21 * *a1
- 26 * a1[1]
- 90 * a1[2]
- 15 * a1[4]
- 54 * a1[7]
- 12 * a1[8]
- 38 * a1[15]
- 15 * a1[16]
- 56 * a1[22] == 57169
&& 71 * a1[18]
+ 39 * a1[17]
+ 73 * a1[15]
+ 14 * a1[14]
+ 56 * a1[12]
+ 56 * a1[10]
+ 27 * a1[9]
+ 68 * a1[7]
+ 39 * a1[6]
+ 26 * a1[5]
+ 40 * a1[4]
+ 24 * a1[3]
+ 11 * a1[2]
+ 14 * a1[1]
+ 94 * *a1
- 10 * a1[8]
- 11 * a1[11]
- 63 * a1[13]
- 39 * a1[16]
- 14 * a1[19]
- 17 * a1[20]
- 23 * a1[21]
- 7 * a1[22] == 40024
&& (a1[22] << 6)
+ 80 * a1[21]
+ 89 * a1[20]
+ 70 * a1[19]
+ 66 * a1[18]
+ 55 * a1[17]
+ 16 * a1[16]
+ 84 * a1[13]
+ 48 * a1[12]
+ 11 * a1[7]
+ 32 * a1[5]
+ 99 * *a1
- 26 * a1[1]
- 91 * a1[2]
- 96 * a1[3]
- 63 * a1[4]
- 67 * a1[6]
- 72 * a1[8]
+ 4 * a1[9]
- 84 * a1[10]
- 81 * a1[11]
- 80 * a1[14]
- 98 * a1[15] == 432
&& a1[21]
+ 41 * a1[17]
+ 46 * a1[12]
+ 44 * a1[9]
+ 63 * *a1
- 73 * a1[1]
- 43 * a1[2]
+ 4 * a1[3]
- 37 * a1[4]
- 54 * a1[5]
- 58 * a1[6]
- 95 * a1[7]
- 2 * a1[8]
- 37 * a1[10]
- 5 * a1[11]
+ 2 * a1[13]
- 46 * a1[14]
- 27 * a1[15]
- 19 * a1[16]
- 78 * a1[18]
- 51 * a1[19]
- 82 * a1[20]
- 59 * a1[22] == -57338
&& 10 * a1[22]
+ 58 * a1[18]
+ 16 * a1[17]
+ 69 * a1[16]
+ 6 * a1[15]
+ 5 * a1[12]
+ 87 * a1[7]
+ 47 * a1[5]
+ 91 * a1[4]
+ 54 * a1[2]
+ 21 * a1[1]
+ 52 * *a1
- 76 * a1[3]
- 96 * a1[6]
- 27 * a1[8]
- 43 * a1[9]
- 15 * a1[10]
- 35 * a1[11]
- 53 * a1[13]
+ 4 * a1[14]
- 83 * a1[19]
- 68 * a1[20]
- 18 * a1[21] == 1777
&& 66 * a1[22]
+ 92 * a1[21]
+ 29 * a1[20]
+ 42 * a1[19]
+ 55 * a1[14]
+ 72 * a1[13]
+ 40 * a1[12]
+ 31 * a1[10]
+ 88 * a1[9]
+ 61 * a1[8]
+ 59 * a1[7]
+ 35 * a1[6]
+ 16 * a1[3]
+ 24 * a1[1]
+ 60 * *a1
- 55 * a1[2]
- 8 * a1[4]
- 7 * a1[5]
- 17 * a1[11]
- 25 * a1[15]
- 22 * a1[16]
- 10 * a1[17]
- 59 * a1[18] == 47727
&& 3 * a1[21]
+ 54 * a1[18]
+ 6 * a1[15]
+ 93 * a1[14]
+ 74 * a1[10]
+ 6 * a1[7]
+ 98 * a1[4]
+ 65 * a1[3]
+ 84 * a1[2]
+ 18 * a1[1]
+ 35 * *a1
- 29 * a1[5]
- 40 * a1[6]
- 35 * a1[8]
+ 8 * a1[9]
- 15 * a1[11]
- 4 * a1[12]
- 83 * a1[16]
- 74 * a1[17]
- 72 * a1[19]
- 53 * a1[20]
- 31 * a1[22] == 6695
&& 45 * a1[20]
+ 14 * a1[19]
+ 76 * a1[18]
+ 17 * a1[16]
+ 86 * a1[14]
+ 28 * a1[11]
+ 19 * a1[5]
+ 46 * a1[1]
+ 75 * *a1
- 12 * a1[2]
- 27 * a1[3]
- 66 * a1[4]
- 27 * a1[6]
- 32 * a1[7]
- 69 * a1[8]
- 31 * a1[9]
- 65 * a1[10]
- 54 * a1[12]
- 6 * a1[13]
+ 2 * a1[15]
- 10 * a1[17]
- 89 * a1[21]
- 16 * a1[22] == -3780
&& 62 * a1[21]
+ 74 * a1[20]
+ 28 * a1[18]
+ 7 * a1[17]
+ 74 * a1[16]
+ 45 * a1[15]
+ 57 * a1[14]
+ 34 * a1[11]
+ 85 * a1[10]
+ 98 * a1[6]
+ 29 * a1[4]
+ 94 * a1[3]
+ 51 * a1[2]
+ 85 * a1[1]
- 36 * a1[5]
- a1[7]
- 3 * a1[8]
- 74 * a1[9]
- 70 * a1[12]
- 68 * a1[13]
- 3 * a1[19]
+ 8 * a1[22] == 47300
&& 22 * a1[22]
+ 45 * a1[21]
+ 14 * a1[19]
+ 32 * a1[18]
+ 77 * a1[17]
+ 70 * a1[12]
+ 7 * a1[10]
+ 99 * a1[4]
+ 82 * *a1
- 48 * a1[1]
- 40 * a1[2]
- 81 * a1[3]
- 27 * a1[5]
- 75 * a1[6]
- 79 * a1[7]
- 26 * a1[8]
- 68 * a1[9]
- 57 * a1[11]
- 77 * a1[13]
- 32 * a1[14]
- a1[15]
- 91 * a1[16]
- 14 * a1[20] == -34153
&& 65 * a1[21]
+ 13 * a1[20]
+ 61 * a1[17]
+ 97 * a1[13]
+ 24 * a1[10]
+ 40 * a1[5]
+ 20 * *a1
- 81 * a1[1]
- 17 * a1[2]
- 77 * a1[3]
- 79 * a1[4]
- 45 * a1[6]
- 61 * a1[7]
- 48 * a1[8]
- 97 * a1[9]
- 49 * a1[11]
- 14 * a1[12]
- 81 * a1[14]
- 20 * a1[15]
- 27 * a1[16]
- 89 * a1[18]
- 93 * a1[19]
- 46 * a1[22] == -55479
&& 60 * a1[21]
+ 70 * a1[20]
+ 13 * a1[15]
+ 87 * a1[13]
+ 76 * a1[11]
+ 88 * a1[9]
+ 87 * a1[3]
+ 87 * *a1
- 97 * a1[1]
- 40 * a1[2]
- 49 * a1[4]
- 23 * a1[5]
- 30 * a1[6]
- 50 * a1[7]
- 98 * a1[8]
- 21 * a1[10]
- 54 * a1[12]
- 65 * a1[14]
- 80 * a1[17]
- 28 * a1[18]
- 57 * a1[19]
- 70 * a1[22] == -20651
&& 54 * a1[20]
+ 86 * a1[17]
+ 92 * a1[16]
+ 41 * a1[15]
+ 70 * a1[10]
+ 9 * a1[9]
+ a1[8]
+ 96 * a1[7]
+ 45 * a1[6]
+ 78 * a1[5]
+ 3 * a1[4]
+ 90 * a1[3]
+ 71 * a1[2]
+ 96 * *a1
- 8 * a1[1]
+ 4 * a1[11]
- 55 * a1[12]
- 73 * a1[13]
- 54 * a1[14]
- 89 * a1[18]
- (a1[19] << 6)
- 67 * a1[21]
+ 4 * a1[22] == 35926
&& 5 * a1[22]
+ 88 * a1[20]
+ 52 * a1[19]
+ 21 * a1[17]
+ 25 * a1[16]
+ 3 * a1[13]
+ 88 * a1[10]
+ 39 * a1[8]
+ 48 * a1[7]
+ 74 * a1[6]
+ 86 * a1[4]
+ 46 * a1[2]
+ 17 * *a1
- 98 * a1[1]
- 50 * a1[3]
- 28 * a1[5]
- 73 * a1[9]
- 33 * a1[11]
- 75 * a1[12]
- 14 * a1[14]
- 31 * a1[15]
- 26 * a1[18]
- 52 * a1[21] == 8283
&& 96 * a1[22]
+ 85 * a1[20]
+ 55 * a1[19]
+ 99 * a1[13]
+ 19 * a1[11]
+ 77 * a1[10]
+ 52 * a1[9]
+ 66 * a1[8]
+ 96 * a1[6]
+ 72 * a1[4]
+ 90 * a1[3]
+ 60 * a1[1]
+ 94 * *a1
- 99 * a1[2]
- 26 * a1[5]
- 94 * a1[7]
- 49 * a1[12]
- 32 * a1[14]
- 54 * a1[15]
- 92 * a1[16]
- 71 * a1[17]
- 63 * a1[18]
- 23 * a1[21] == 33789
&& 15 * a1[22]
+ a1[19]
+ 26 * a1[17]
+ 65 * a1[16]
+ 80 * a1[11]
+ 92 * a1[8]
+ 28 * a1[5]
+ 79 * a1[4]
+ 73 * *a1
- 98 * a1[1]
- 2 * a1[2]
- 70 * a1[3]
- 10 * a1[6]
- 30 * a1[7]
- 51 * a1[9]
- 77 * a1[10]
- 32 * a1[12]
- 32 * a1[13]
+ 8 * a1[14]
+ 4 * a1[15]
- 11 * a1[18]
- 83 * a1[20]
- 85 * a1[21] == -10455;
}

可以看到,这一大长串包含了22个等式,对a1[0]a1[22]共23个变量进行了约束,

值得注意的是:

  • *a1其实就是a1[0],第一个变量
  • a1[i] << 6 = 64 * a1[i] (左移6位实际上就是*64)

根据_main函数的汇编代码,得到是z3算法,

编写最终的EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
from z3 import *

x = [Int(f'x{i}') for i in range(23)]
s = Solver()
for i in range(23):
s.add(x[i] >= 32, x[i] <= 126)

s.add(
94*x[22] + 74*x[21] + 70*x[19] + 12*x[18] + 20*x[16] + 62*x[12] + 82*x[10] +
7*x[7] + 63*x[6] + 18*x[5] + 58*x[4] + 94*x[2] + 77*x[0] -
43*x[1] - 37*x[3] - 97*x[8] - 23*x[9] - 86*x[11] - 6*x[13] - 5*x[14] -
79*x[15] - 63*x[17] - 93*x[20] == 20156
)

s.add(
87*x[22] + 75*x[21] + 73*x[15] + 67*x[14] + 30*x[13] + 64*x[11] + 35*x[9] +
91*x[7] + 91*x[5] + 34*x[3] + 74*x[0] -
89*x[1] - 72*x[2] - 76*x[4] - 32*x[6] - 97*x[8] - 39*x[10] - 23*x[12] +
8*x[16] - 98*x[17] - 4*x[18] - 80*x[19] - 83*x[20] == 7183
)

s.add(
51*x[21] + 22*x[20] + 15*x[19] + 51*x[17] + 96*x[12] + 34*x[7] + 77*x[5] +
59*x[2] + 89*x[1] + 92*x[0] -
85*x[3] - 50*x[4] - 51*x[6] - 75*x[8] - 40*x[10] - 4*x[11] - 74*x[13] -
98*x[14] - 23*x[15] - 14*x[16] - 92*x[18] - 7*x[22] == -7388
)

s.add(
61*x[22] + 72*x[21] + 28*x[20] + 55*x[18] + 20*x[17] + 13*x[14] + 51*x[13] +
69*x[12] + 10*x[11] + 95*x[10] + 43*x[9] + 53*x[8] + 76*x[7] + 25*x[6] +
9*x[5] + 10*x[4] + 98*x[1] + 70*x[0] -
22*x[2] + 2*x[3] - 49*x[15] + 4*x[16] - 77*x[19] == 69057
)

s.add(
7*x[22] + 21*x[16] + 22*x[13] + 55*x[9] + 66*x[8] + 78*x[5] + 10*x[3] +
80*x[1] + 65*x[0] -
20*x[2] - 53*x[4] - 98*x[6] + 8*x[7] - 78*x[10] - 94*x[11] - 93*x[12] -
18*x[14] - 48*x[15] - 9*x[17] - 73*x[18] - 59*x[19] - 68*x[20] - 74*x[21] == -31438
)

s.add(
33*x[19] + 78*x[15] + 66*x[10] + 3*x[9] + 43*x[4] + 24*x[3] + 3*x[2] +
27*x[0] -
18*x[1] - 46*x[5] - 18*x[6] - x[7] - 33*x[8] - 50*x[11] - 23*x[12] -
37*x[13] - 45*x[14] + 2*x[16] - x[17] - 60*x[18] - 87*x[20] - 72*x[21] - 6*x[22] == -26121
)

s.add(
31*x[20] + 80*x[18] + 34*x[17] + 34*x[15] + 38*x[14] + 53*x[13] + 35*x[12] +
82*x[9] + 27*x[8] + 80*x[7] + 46*x[6] + 18*x[4] + 5*x[1] + 98*x[0] -
12*x[2] - 9*x[3] - 57*x[5] - 46*x[10] - 31*x[11] - 68*x[16] - 94*x[19] -
93*x[21] - 15*x[22] == 26005
)

s.add(
81*x[21] + 40*x[20] + 34*x[19] + 94*x[18] + 98*x[17] + 11*x[14] + 63*x[13] +
95*x[12] + 43*x[11] + 99*x[10] + 29*x[9] + 81*x[6] + 72*x[5] + 54*x[3] +
21*x[0] -
26*x[1] - 90*x[2] - 15*x[4] - 54*x[7] - 12*x[8] - 38*x[15] - 15*x[16] - 56*x[22] == 57169
)

s.add(
71*x[18] + 39*x[17] + 73*x[15] + 14*x[14] + 56*x[12] + 56*x[10] + 27*x[9] +
68*x[7] + 39*x[6] + 26*x[5] + 40*x[4] + 24*x[3] + 11*x[2] + 14*x[1] + 94*x[0] -
10*x[8] - 11*x[11] - 63*x[13] - 39*x[16] - 14*x[19] - 17*x[20] - 23*x[21] - 7*x[22] == 40024
)

s.add(
64*x[22] + 80*x[21] + 89*x[20] + 70*x[19] + 66*x[18] + 55*x[17] + 16*x[16] +
84*x[13] + 48*x[12] + 11*x[7] + 32*x[5] + 99*x[0] -
26*x[1] - 91*x[2] - 96*x[3] - 63*x[4] - 67*x[6] - 72*x[8] + 4*x[9] -
84*x[10] - 81*x[11] - 80*x[14] - 98*x[15] == 432
)

s.add(
x[21] + 41*x[17] + 46*x[12] + 44*x[9] + 63*x[0] -
73*x[1] - 43*x[2] + 4*x[3] - 37*x[4] - 54*x[5] - 58*x[6] - 95*x[7] -
2*x[8] - 37*x[10] - 5*x[11] + 2*x[13] - 46*x[14] - 27*x[15] - 19*x[16] -
78*x[18] - 51*x[19] - 82*x[20] - 59*x[22] == -57338
)

s.add(
10*x[22] + 58*x[18] + 16*x[17] + 69*x[16] + 6*x[15] + 5*x[12] + 87*x[7] +
47*x[5] + 91*x[4] + 54*x[2] + 21*x[1] + 52*x[0] -
76*x[3] - 96*x[6] - 27*x[8] - 43*x[9] - 15*x[10] - 35*x[11] - 53*x[13] +
4*x[14] - 83*x[19] - 68*x[20] - 18*x[21] == 1777
)

s.add(
66*x[22] + 92*x[21] + 29*x[20] + 42*x[19] + 55*x[14] + 72*x[13] + 40*x[12] +
31*x[10] + 88*x[9] + 61*x[8] + 59*x[7] + 35*x[6] + 16*x[3] + 24*x[1] + 60*x[0] -
55*x[2] - 8*x[4] - 7*x[5] - 17*x[11] - 25*x[15] - 22*x[16] - 10*x[17] - 59*x[18] == 47727
)

s.add(
3*x[21] + 54*x[18] + 6*x[15] + 93*x[14] + 74*x[10] + 6*x[7] + 98*x[4] + 65*x[3] +
84*x[2] + 18*x[1] + 35*x[0] -
29*x[5] - 40*x[6] - 35*x[8] + 8*x[9] - 15*x[11] - 4*x[12] - 83*x[16] -
74*x[17] - 72*x[19] - 53*x[20] - 31*x[22] == 6695
)

s.add(
45*x[20] + 14*x[19] + 76*x[18] + 17*x[16] + 86*x[14] + 28*x[11] + 19*x[5] +
46*x[1] + 75*x[0] -
12*x[2] - 27*x[3] - 66*x[4] - 27*x[6] - 32*x[7] - 69*x[8] - 31*x[9] -
65*x[10] - 54*x[12] - 6*x[13] + 2*x[15] - 10*x[17] - 89*x[21] - 16*x[22] == -3780
)

s.add(
62*x[21] + 74*x[20] + 28*x[18] + 7*x[17] + 74*x[16] + 45*x[15] + 57*x[14] +
34*x[11] + 85*x[10] + 98*x[6] + 29*x[4] + 94*x[3] + 51*x[2] + 85*x[1] -
36*x[5] - x[7] - 3*x[8] - 74*x[9] - 70*x[12] - 68*x[13] - 3*x[19] + 8*x[22] == 47300
)

s.add(
22*x[22] + 45*x[21] + 14*x[19] + 32*x[18] + 77*x[17] + 70*x[12] + 7*x[10] +
99*x[4] + 82*x[0] -
48*x[1] - 40*x[2] - 81*x[3] - 27*x[5] - 75*x[6] - 79*x[7] - 26*x[8] -
68*x[9] - 57*x[11] - 77*x[13] - 32*x[14] - x[15] - 91*x[16] - 14*x[20] == -34153
)

s.add(
65*x[21] + 13*x[20] + 61*x[17] + 97*x[13] + 24*x[10] + 40*x[5] + 20*x[0] -
81*x[1] - 17*x[2] - 77*x[3] - 79*x[4] - 45*x[6] - 61*x[7] - 48*x[8] -
97*x[9] - 49*x[11] - 14*x[12] - 81*x[14] - 20*x[15] - 27*x[16] - 89*x[18] -
93*x[19] - 46*x[22] == -55479
)

s.add(
60*x[21] + 70*x[20] + 13*x[15] + 87*x[13] + 76*x[11] + 88*x[9] + 87*x[3] + 87*x[0] -
97*x[1] - 40*x[2] - 49*x[4] - 23*x[5] - 30*x[6] - 50*x[7] - 98*x[8] -
21*x[10] - 54*x[12] - 65*x[14] - 80*x[17] - 28*x[18] - 57*x[19] - 70*x[22] == -20651
)

s.add(
54*x[20] + 86*x[17] + 92*x[16] + 41*x[15] + 70*x[10] + 9*x[9] + x[8] +
96*x[7] + 45*x[6] + 78*x[5] + 3*x[4] + 90*x[3] + 71*x[2] + 96*x[0] -
8*x[1] + 4*x[11] - 55*x[12] - 73*x[13] - 54*x[14] - 89*x[18] - 64*x[19] -
67*x[21] + 4*x[22] == 35926
)

s.add(
5*x[22] + 88*x[20] + 52*x[19] + 21*x[17] + 25*x[16] + 3*x[13] + 88*x[10] +
39*x[8] + 48*x[7] + 74*x[6] + 86*x[4] + 46*x[2] + 17*x[0] -
98*x[1] - 50*x[3] - 28*x[5] - 73*x[9] - 33*x[11] - 75*x[12] - 14*x[14] -
31*x[15] - 26*x[18] - 52*x[21] == 8283
)

s.add(
96*x[22] + 85*x[20] + 55*x[19] + 99*x[13] + 19*x[11] + 77*x[10] + 52*x[9] +
66*x[8] + 96*x[6] + 72*x[4] + 90*x[3] + 60*x[1] + 94*x[0] -
99*x[2] - 26*x[5] - 94*x[7] - 49*x[12] - 32*x[14] - 54*x[15] - 92*x[16] -
71*x[17] - 63*x[18] - 23*x[21] == 33789
)

s.add(
15*x[22] + x[19] + 26*x[17] + 65*x[16] + 80*x[11] + 92*x[8] + 28*x[5] +
79*x[4] + 73*x[0] -
98*x[1] - 2*x[2] - 70*x[3] - 10*x[6] - 30*x[7] - 51*x[9] - 77*x[10] -
32*x[12] - 32*x[13] + 8*x[14] + 4*x[15] - 11*x[18] - 83*x[20] - 85*x[21] == -10455
)

if s.check() == sat:
m = s.model()
x_vals = [m[x[i]].as_long() for i in range(23)]
flag_bytes = bytes([xi ^ 0xC for xi in x_vals])
print("Flag:", flag_bytes.decode('ascii'))
else:
print("No solution!")

# Flag: ISCTF{yR_A_Zzz_Ma5t3R!}

ezpy


题目描述:这是什么库?没见过呢


下载附件,是pyinstaller处理的ezpy.exe,按照之前做法,得到extracted文件夹,

反编译ezpy.pyc得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
try:
from mypy import check

def main():
user_input = input('Please input your flag: ').strip()
if check(user_input):
print('Correct!')
return None
if __name__ == '__main__':
main()
except ImportError:
print('Error: Cannot import mypy module')
exit(1)

没什么用,继续找。在目录里看到了mypy.cp313-win_amd64.pyd,想着用IDA反编译试试…

在IDA中,Shift+F12看到RC4 flag checker module,得到是RC4加密

通过一个一个函数查看的艰难寻找,在sub_36F4D1519函数中得到RC4加密的密钥ISCTF2025

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
char *v2; // rsi
__m128i *v3; // rbx
__m128i *v5; // rax
unsigned int v6; // eax
__int64 v7; // rax
char v8[274]; // [rsp+26h] [rbp-132h] BYREF
char *Str; // [rsp+138h] [rbp-20h] BYREF

strcpy(v8, "ISCTF2025");
if ( !(unsigned int)PyArg_ParseTuple(a2, &unk_36F4D4000, &Str) )
return 0LL;
v2 = Str;
v3 = (__m128i *)Py_FalseStruct;
if ( (unsigned int)strlen(Str) == 25 )
{
v5 = (__m128i *)malloc(0x19uLL);
v3 = v5;
if ( v5 )
{
*v5 = _mm_loadu_si128((const __m128i *)v2);
*(__m128i *)((char *)v5 + 9) = _mm_loadu_si128((const __m128i *)(v2 + 9));
v6 = strlen(v8);
sub_36F4D1430(&v8[10], v8, v6);
sub_36F4D149C(&v8[10], v3, 25LL);
v7 = 0LL;
while ( v3->m128i_i8[v7] == byte_36F4D4050[v7] )
{
if ( ++v7 == 25 )
{
free(v3);
return (__m128i *)Py_TrueStruct;
}
}
free(v3);
return (__m128i *)Py_FalseStruct;
}
else
{
PyErr_NoMemory();
}
}
return v3;
}

生成RC4的S-box,写入v8[i],然后执行cipher[i] = plain[i] XOR RC4_next()

查看汇编代码,得到byte_36F4D4050的数据:

re1

最终的EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
cipher = bytes([
0x1D,0xD5,0x38,0x33,0xAF,0xB5,0x51,0xF3,0x2C,0x6B,
0x6E,0xFE,0x41,0x24,0x43,0xD2,0x71,0xCF,0xA4,0x4C,
0xE3,0x9A,0x9A,0xB5,0x31
])

key = b"ISCTF2025"

def rc4_ksa(key):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) & 0xFF
S[i], S[j] = S[j], S[i]
return S

def rc4_prga(S, n):
i = j = 0
out = []
for _ in range(n):
i = (i + 1) & 0xFF
j = (j + S[i]) & 0xFF
S[i], S[j] = S[j], S[i]
K = S[(S[i] + S[j]) & 0xFF]
out.append(K)
return bytes(out)

S = rc4_ksa(key)
keystream = rc4_prga(S, len(cipher))

plain = bytes([c ^ k for c, k in zip(cipher, keystream)])
print(plain)

# flag: ISCTF{Y0U_GE7_7HE_PYD!!!}

MysteriousStream


题目描述:小曲冒着生命风险,读入了一个神秘的 payload.dat文件,为了不枉费小曲的艰辛……,你能逆向出被加密的秘密吗?


下载附件,包含challengepayload.dat文件,定位至main函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
{
FILE *v3; // rax
FILE *v4; // r12
signed __int64 v5; // r14
char *v6; // rax
char *v7; // rbp
size_t v8; // r13
__int64 i; // rcx
_BYTE v11[17]; // [rsp+7h] [rbp-41h] BYREF
unsigned __int64 v12; // [rsp+18h] [rbp-30h]

v12 = __readfsqword(0x28u);
v3 = fopen("payload.dat", "rb");
if ( v3 )
{
v4 = v3;
fseek(v3, 0LL, 2);
v5 = ftell(v4);
if ( v5 < 0 )
{
puts("Get file size failed");
fclose(v4);
return 1;
}
else
{
fseek(v4, 0LL, 0);
v6 = (char *)malloc(v5);
v7 = v6;
if ( v6 )
{
v8 = fread(v6, 1uLL, v5, v4);
fclose(v4);
if ( v5 == v8 )
{
qmemcpy(v11, "P4ssXORSecr3tK3y!", sizeof(v11));
rc4_variant(v7, v8, &v11[7], 10LL);
if ( v8 )
{
for ( i = 0LL; i != v8; ++i )
v7[i] ^= v11[i % 7];
}
__printf_chk(1LL, "Result: %s\n", v7);
free(v7);
return 0;
}
else
{
__printf_chk(1LL, "Read failed! Expected %ld bytes, got %zu bytes\n", v5, v8);
free(v7);
return 1;
}
}
else
{
puts("Malloc memory failed");
fclose(v4);
return 1;
}
}
}
else
{
puts("payload.dat not found");
return 1;
}
}

使用key = v11[7 : 7 + 10] = "Secr3tK3y!"加密,对payload (v7) 做RC4加密,

然后循环异或key_xor = v11[0:7] = b"P4ssXOR"v7[i] = v7[i] XOR key_xor[i % 7]

再看xor_cycle函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
unsigned __int64 i; // r8
__int64 result; // rax

if ( a2 )
{
for ( i = 0LL; i != a2; ++i )
{
result = *(unsigned __int8 *)(a3 + i % a4);
*(_BYTE *)(a1 + i) ^= result;
}
}
return result;
}

rc4_variant函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{
_BYTE *v4; // r8
__int64 i; // rax
unsigned __int64 v7; // rcx
int v8; // ebx
char v9; // r11
_BYTE *v10; // r9
char v11; // al
_BYTE v13[264]; // [rsp+0h] [rbp-118h]
unsigned __int64 v14; // [rsp+108h] [rbp-10h]

v4 = a1;
v14 = __readfsqword(0x28u);
for ( i = 0LL; i != 256; ++i )
v13[i] = i;
v7 = 0LL;
LOBYTE(v8) = 0;
do
{
v9 = v13[v7];
v8 = (unsigned __int8)((v7 & 0xAA) + v8 + v9 + *(_BYTE *)(a3 + v7 % a4));
v13[v7++] = v13[v8];
v13[v8] = v9;
}
while ( v7 != 256 );
if ( a2 )
{
v10 = &a1[a2];
LOBYTE(a1) = 0;
LOBYTE(a2) = 0;
do
{
LODWORD(a1) = (unsigned __int8)((_BYTE)a1 + 1);
v11 = v13[(unsigned int)a1];
LODWORD(a2) = (unsigned __int8)(v11 + a2);
v13[(unsigned int)a1] = v13[(unsigned int)a2];
v13[(unsigned int)a2] = v11;
*v4++ ^= v13[(unsigned __int8)(v13[(unsigned int)a1] + v11)];
}
while ( v10 != v4 );
}
return v14 - __readfsqword(0x28u);
}

变种的RC4加密逻辑为j = (j + S[i] + key[i % keylen] + (i & 0xAA)) mod 256,解密只需逆着来即可。

所以,最终的加密逻辑为cipher = XOR( RC4_variant(plaintext, key="Secr3tK3y!") , key="P4ssXOR")

EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def rc4_variant_crypt(data: bytes, key: bytes) -> bytes:

S = list(range(256))
j = 0
key_len = len(key)
for i in range(256):
j = ( (i & 0xAA) + j + S[i] + key[i % key_len] ) & 0xFF
S[i], S[j] = S[j], S[i]

out = bytearray()
i = 0
j = 0
for byte in data:
i = (i + 1) & 0xFF
j = (j + S[i]) & 0xFF
S[i], S[j] = S[j], S[i]
K = S[(S[i] + S[j]) & 0xFF]
out.append(byte ^ K)

return bytes(out)


def decrypt(cipher: bytes) -> bytes:
xor_key = b"P4ssXOR"
rc4_key = b"Secr3tK3y!"

tmp = bytearray(len(cipher))
for i in range(len(cipher)):
tmp[i] = cipher[i] ^ xor_key[i % len(xor_key)]

plain = rc4_variant_crypt(tmp, rc4_key)
return plain

if __name__ == "__main__":
with open("D:\\MysteriousStream\\payload.dat", "rb") as f:
cipher = f.read()
plaintext = decrypt(cipher)
print(plaintext.decode(errors="ignore"))

# flag: ISCTF{Y0u_a2e_2ea11y_a_1aby2inth_master}

CRYPTO

easy_RSA


题目描述:我们的爱情像欧拉函数φ(n)——无限趋近却永远达不到n的完美互质,最终只剩周期性的怀念在模n的世界里循环证明


下载加密代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from Crypto.Util.number import *

p = getPrime(1024)

q = getPrime(1024)

N = p*q

e = 65537

msg = bytes_to_long(b"ISCTF{dummy_flag}")

ct1 = pow(msg, e, N)

ct2 = pow(msg, p+q, N)

print(f"{N = }")

print(f"{ct1 = }")

print(f"{ct2 = }")

"""
N = 17630258257080557797062320474423515967705950026415012912087655679315479168903980901728425140787005046038000068414269936806478828260848859753400786557270120330760791255046985114127285672634413513991988895166115794242018674042563788348381567565190146278040811257757119090296478610798393944581870309373529884950663990485525646200034220648901490835962964029936321155200390798215987316069871958913773199197073860062515329879288106446016695204426001393566351524023857332978260894409698596465474214898402707157933326431896629025197964209580991821222557663589475589423032130993456522178540455360695933336455068507071827928617
ct1 = 5961639119243884817956362325106436035547108981120248145301572089585639543543496627985540773185452108709958107818159430835510386993354596106366458898765597405461225798615020342640056386757104855709899089816838805631480329264128349465229327090721088394549641366346516133008681155817222994359616737681983784274513555455340301061302815102944083173679173923728968671113926376296481298323500774419099682647601977970777260084799036306508597807029122276595080580483336115458713338522372181732208078117809553781889555191883178157241590455408910096212697893247529197116309329028589569527960811338838624831855672463438531266455
ct2 = 11792054298654397865983651507912282632831471680334312509918945120797862876661899077559686851237832931501121869814783150387308320349940383857026679141830402807715397332316601439614741315278033853646418275632174160816784618982743834204997402866931295619202826633629690164429512723957241072421663170829944076753483616865208617479794763412611604625495201470161813033934476868949612651276104339747165276204945125001274777134529491152840672010010940034503257315555511274325831684793040209224816879778725612468542758777428888563266233284958660088175139114166433501743740034567850893745466521144371670962121062992082312948789
"""

是RSA中的共模攻击,m = c1 ^ s1 * c2 ^ s2 mod N

得到EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from Crypto.Util.number import long_to_bytes, inverse

N = 17630258257080557797062320474423515967705950026415012912087655679315479168903980901728425140787005046038000068414269936806478828260848859753400786557270120330760791255046985114127285672634413513991988895166115794242018674042563788348381567565190146278040811257757119090296478610798393944581870309373529884950663990485525646200034220648901490835962964029936321155200390798215987316069871958913773199197073860062515329879288106446016695204426001393566351524023857332978260894409698596465474214898402707157933326431896629025197964209580991821222557663589475589423032130993456522178540455360695933336455068507071827928617
ct1 = 5961639119243884817956362325106436035547108981120248145301572089585639543543496627985540773185452108709958107818159430835510386993354596106366458898765597405461225798615020342640056386757104855709899089816838805631480329264128349465229327090721088394549641366346516133008681155817222994359616737681983784274513555455340301061302815102944083173679173923728968671113926376296481298323500774419099682647601977970777260084799036306508597807029122276595080580483336115458713338522372181732208078117809553781889555191883178157241590455408910096212697893247529197116309329028589569527960811338838624831855672463438531266455
ct2 = 11792054298654397865983651507912282632831471680334312509918945120797862876661899077559686851237832931501121869814783150387308320349940383857026679141830402807715397332316601439614741315278033853646418275632174160816784618982743834204997402866931295619202826633629690164429512723957241072421663170829944076753483616865208617479794763412611604625495201470161813033934476868949612651276104339747165276204945125001274777134529491152840672010010940034503257315555511274325831684793040209224816879778725612468542758777428888563266233284958660088175139114166433501743740034567850893745466521144371670962121062992082312948789

e1 = 65537
e2 = N + 1

def extended_gcd(a, b):
if a == 0:
return b, 0, 1
else:
g, y, x = extended_gcd(b % a, a)
return g, x - (b // a) * y, y

g, s1, s2 = extended_gcd(e1, e2)

print(f"[*] gcd(e1, e2) = {g}")
print(f"[*] s1 = {s1}")
print(f"[*] s2 = {s2}")

if s1 > 0:
part1 = pow(ct1, s1, N)
else:
part1 = pow(inverse(ct1, N), -s1, N)

if s2 > 0:
part2 = pow(ct2, s2, N)
else:
part2 = pow(inverse(ct2, N), -s2, N)

msg_int = (part1 * part2) % N
flag = long_to_bytes(msg_int)

print("-" * 30)
print(f"[*] Decrypted Flag: {flag}")
try:
print(f"[*] Decoded: {flag.decode()}")
except:
pass
print("-" * 30)

# flag: ISCTF{Congratulations_you_master_Mathematical_ability}

小蓝鲨的LFSR系统


题目描述:”小蓝鲨是海洋情报局的新晋密码专家,它设计了一个基于LFSR的流密码系统来加密机密信息。这个系统看起来简单高效,但小蓝鲨不知道的是,LFSR在某些情况下可能存在安全隐患。 一天,小蓝鲨的加密系统被神秘的黑客组织””深海幽灵””入侵,他们截获了一段加密信息。作为海洋安全部门的成员,你需要分析这个加密系统,找出潜在的弱点,并解密被截获的信息。”


打开附件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import secrets
import binascii

def simple_lfsr_encrypt(plaintext, init_state):
mask = [random.randint(0,1) for _ in range(128)]

state = init_state.copy()
for _ in range(256):
feedback = sum(state[i] & mask[i] for i in range(128)) % 2
state.append(feedback)

key = bytes(int(''.join(str(bit) for bit in mask[i*8:(i+1)*8]), 2)
for i in range(16))

keystream = (key * (len(plaintext)//16 + 1))[:len(plaintext)]
return bytes(p ^ k for p, k in zip(plaintext, keystream)), mask

和对应的输出文件:

1
2
3
initState = [0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0]
outputState = [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1]
ciphertext = '4b3be165a0a0edd67ca8f143884826725107fd42d6a6'

构造线性方程组A * X = B,在GF(2)域上使用高斯消元法解出mask

EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import binascii

initState = [0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0]

outputState = [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1]

ciphertext_hex = '4b3be165a0a0edd67ca8f143884826725107fd42d6a6'

full_stream = initState + outputState
N = 128

def gaussian_elimination_gf2(A, B):
rows = len(A)
cols = len(A[0])
aug_matrix = [row + [B[i]] for i, row in enumerate(A)]

pivot_row = 0
for col in range(cols):
if pivot_row >= rows: break
if aug_matrix[pivot_row][col] == 0:
for i in range(pivot_row + 1, rows):
if aug_matrix[i][col] == 1:
aug_matrix[pivot_row], aug_matrix[i] = aug_matrix[i], aug_matrix[pivot_row]
break
else: continue
for i in range(rows):
if i != pivot_row and aug_matrix[i][col] == 1:
aug_matrix[i] = [x ^ y for x, y in zip(aug_matrix[i], aug_matrix[pivot_row])]
pivot_row += 1

solution = [0] * cols
for i in range(rows):
try:
pivot_col = aug_matrix[i][:-1].index(1)
solution[pivot_col] = aug_matrix[i][-1]
except ValueError: pass
return solution

matrix = []
results = []
num_equations = len(outputState)
print(f"[*] Building {num_equations} equations from stream...")

for i in range(min(num_equations, N + 20)):
row = full_stream[i : i + N]
res = full_stream[i + N]
matrix.append(row)
results.append(res)

print("[*] Solving for Mask via Gaussian Elimination...")
mask = gaussian_elimination_gf2(matrix, results)

print("[*] Verifying Mask...", end=" ")
state_test = initState.copy()
generated_test = []
for _ in range(len(outputState)):
feedback = sum(state_test[k] & mask[k] for k in range(128)) % 2
state_test.append(feedback)

check_pass = True
for i in range(len(outputState)):
prediction = sum(full_stream[i+k] & mask[k] for k in range(128)) % 2
if prediction != outputState[i]:
check_pass = False
break

if check_pass:
print("SUCCESS! Mask perfectly regenerates the output.")
else:
print("WARNING: Mask verification failed. The LFSR logic might differ.")

def decrypt_with_mode(mask_bits, ct_hex, mode_name):
key_bytes = []
for i in range(16):
bits = mask_bits[i*8 : (i+1)*8]
if "Little" in mode_name:
bits = bits[::-1]

val = int(''.join(str(b) for b in bits), 2)
key_bytes.append(val)

key = bytes(key_bytes)
ct = binascii.unhexlify(ct_hex)
keystream = (key * (len(ct)//16 + 1))[:len(ct)]
pt = bytes(c ^ k for c, k in zip(ct, keystream))

try:
pt_text = pt.decode('utf-8')
if "ISCTF{" in pt_text or "uuid" in pt_text or "{" in pt_text:
print(f"\n[+] SUCCESS ({mode_name}): {pt_text}")
else:
if all(32 <= c <= 126 for c in pt):
print(f"\n[?] Possible Candidate ({mode_name}): {pt_text}")
except:
pass
return pt

print("-" * 30)
print("[*] Attempting Decryption...")

res1 = decrypt_with_mode(mask, ciphertext_hex, "Standard Big-Endian")
res2 = decrypt_with_mode(mask, ciphertext_hex, "Little-Endian Bits")

print("-" * 30)
print(f"Key (Hex): {bytes(int(''.join(str(b) for b in mask[i*8:(i+1)*8]), 2) for i in range(16)).hex()}")

# flag: ISCTF{lf5R_jUst_So_s0}

小蓝鲨的RSA密文


题目描述:”小蓝鲨是海洋数学天才,它最近正在深耕RSA领域。你嗤之以鼻,心想RSA不是最基础的密码学知识吗?于是你信誓旦旦的跑到小蓝鲨面前告诉它你已经完全掌握了RSA,并宣称所有的RSA题目你都能做出来。 小蓝鲨意味深长的看了你一眼,并出了一道RSA来考考你。现在,该你向它证明你的实力了。”


打开.py文件,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import json, secrets
from Crypto.Util.number import getPrime, bytes_to_long
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

e = 3
N = getPrime(512) * getPrime(512)

a2_high = a2 >> LOW_BITS

aes_key = secrets.token_bytes(16)
m = bytes_to_long(aes_key)

f = a2 * (m * m) + a1 * m + a0

c = (pow(m, e) + f) % N

iv = secrets.token_bytes(16)
cipher = AES.new(aes_key, AES.MODE_CBC, iv=iv)
ct = cipher.encrypt(pad(FLAG, 16))

"""
N = 121288600621198389662246479277632294800423697823363188896668775456771641807233781416525282234787873435904747571468452950479817935684848143651716343606633656969395065588423982440884464542428742861388200306417822228591316703916504170245990423925894477848679490979364923848426643149659758241239900845544537886777

c = 3756824985347508967549776773725045773059311839370527149219720084008312247164501688241698562854942756369420003479117

a2_high = 9012778

LOW_BITS = 16

a1 = 621315

a0 = 452775142

iv = bf38e64bb5c1b069a07b7d1d046a9010

ct = 8966006c4724faf53883b56a1a8a08ee17b1535e1657c16b3b129ee2d2e389744c943014eb774cd24a5d0f7ad140276fdec72eb985b6de67b8e4674b0bcdc4a5
"""

模数N(两512位素数乘积)过大,而m(AES-key)只有128位

我们可以采用爆破low_bits,遍历0 - 65535的所有可能值,构造完整的a2;再求解三次方程m^3 + a2*m^2 + a1*m + (a0 - c) = 0;用二分查找找到m;最后,用找到的密钥m解密ct即可得到flag。

EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import sys
from Crypto.Util.number import long_to_bytes
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

c = 3756824985347508967549776773725045773059311839370527149219720084008312247164501688241698562854942756369420003479117
a2_high = 9012778
LOW_BITS = 16
a1 = 621315
a0 = 452775142
iv_hex = "bf38e64bb5c1b069a07b7d1d046a9010"
ct_hex = "8966006c4724faf53883b56a1a8a08ee17b1535e1657c16b3b129ee2d2e389744c943014eb774cd24a5d0f7ad140276fdec72eb985b6de67b8e4674b0bcdc4a5"

iv = bytes.fromhex(iv_hex)
ct = bytes.fromhex(ct_hex)

def solve_cubic_for_m(target_a2):
low = 0
high = 1 << 130

while low <= high:
mid = (low + high) // 2
val = mid**3 + target_a2 * (mid**2) + a1 * mid + a0
if val == c:
return mid
elif val < c:
low = mid + 1
else:
high = mid - 1
return None

print("[*] 开始爆破 a2 的低 16 位...")

found_m = None

for low_part in range(2**LOW_BITS):

current_a2 = (a2_high << LOW_BITS) + low_part
res = solve_cubic_for_m(current_a2)

if res is not None:
found_m = res
print(f"[+] 找到唯一解 m: {found_m}")
print(f"[+] 对应的 a2 低位为: {low_part}")
break

if found_m:
try:
aes_key = long_to_bytes(found_m)

if len(aes_key) < 16:
aes_key = aes_key.rjust(16, b'\0')

cipher = AES.new(aes_key, AES.MODE_CBC, iv=iv)
decrypted = cipher.decrypt(ct)

flag = unpad(decrypted, 16)
print(f"\n[SUCCESS] Flag: {flag.decode()}")

except Exception as e:
print(f"[ERROR] 解密失败: {e}")
else:
print("[-] 未找到符合条件的 m")

# flag: ISCTF{i7_533M5_Lik3_You_R34lLy_UNd3R574nd_Polinomials_4nD_RSA}

baby_math


题目描述:死去的记忆突然被唤醒了


打开:

1
2
3
4
5
6
7
8
9
10
11
from Crypto.Util.number import bytes_to_long

print(len(flag))
R = RealField(1000)
a,b = bytes_to_long(flag[:len(flag)//2]),bytes_to_long(flag[len(flag)//2:])
x = R(0.75872961153339387563860550178464795474547887323678173252494265684893323654606628651427151866818730100357590296863274236719073684620030717141521941211167282170567424114270941542016135979438271439047194028943997508126389603529160316379547558098144713802870753946485296790294770557302303874143106908193100)

enc = a*cos(x)+b*sin(x)


#1.24839978408728580181183027675785982784764821592156892598136000363397267152291738689909414790691435938223032351375697399608345468567445269769342300325192248438038963977207296241971217955178443170598629648414706345216797043374408541203167719396818925953801387623884200901703606288664141375049626635852e52

给出a * cos(x) + b * sin(x) = enc,此为背包问题的变种

可以利用```LLL算法``,构造格,构造矩阵使得目标向量为格的一个短向量,利用格基约减求解。

EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from Crypto.Util.number import long_to_bytes
from sage.all import *

x_val_str = "0.75872961153339387563860550178464795474547887323678173252494265684893323654606628651427151866818730100357590296863274236719073684620030717141521941211167282170567424114270941542016135979438271439047194028943997508126389603529160316379547558098144713802870753946485296790294770557302303874143106908193100"
enc_val_str = "1.24839978408728580181183027675785982784764821592156892598136000363397267152291738689909414790691435938223032351375697399608345468567445269769342300325192248438038963977207296241971217955178443170598629648414706345216797043374408541203167719396818925953801387623884200901703606288664141375049626635852e52"

R = RealField(1000)
x = R(x_val_str)
enc = R(enc_val_str)

K = 10**300

M = Matrix(ZZ, [
[1, 0, int(K * cos(x))],
[0, 1, int(K * sin(x))],
[0, 0, int(K * enc)]
])

M_reduced = M.LLL()
vec = M_reduced[0]

a = abs(vec[0])
b = abs(vec[1])

print(f"[+] Found a: {a}")
print(f"[+] Found b: {b}")

try:
part1 = long_to_bytes(a)
part2 = long_to_bytes(b)
flag = part1 + part2
print(f"\n[SUCCESS] Flag: {flag.decode()}")
except Exception as e:
print(f"[-] Decode failed: {e}")

# [SUCCESS] Flag: ISCTF{164a3221-7306-4024-88c3-4ef557b86895}

小蓝鲨的费马谜题


题目描述:小蓝鲨在一次网络探险中发现了一个神秘的加密系统。他发现这个系统好像使用了费马小定理来保护重要信息,但是又好像不太一样。小蓝鲨设法截获了系统的加密输出,但不知道如何解密,你可以帮帮它吗?


打开,还有25KB的output.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import random
import math

p = get_prime(1024)
q = get_prime(1024)
n = p * q
e = 65537

m = bytes_to_long(flag)
c = pow(m, e, n)

bases = get_primes_up_to(100)

hints = []
for i in range(len(bases)):
for j in range(i+1, len(bases)):
hint_value = (pow(bases[i], p-1, n) + pow(bases[j], p-1, n)) % n
hints.append((bases[i], bases[j], hint_value))

根据给定的hint:H(a,b) = a ^ (p - 1) + b ^ (p - 1) mod n

与费马小定理b ^ (p - 1) = c ^ (p - 1) = 1 (mod p)

得出p = gcd(H(a,b) - H(a , c), n)

所以,EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import re
from math import gcd
from Crypto.Util.number import long_to_bytes, inverse

path = "D:\\task\\output.txt"
with open(path, "r", encoding="utf-8") as f:
txt = f.read()

m_n = re.search(r"n\s*=\s*([0-9]+)", txt)
m_e = re.search(r"e\s*=\s*([0-9]+)", txt)
m_c = re.search(r"c\s*=\s*([0-9]+)", txt)
if not (m_n and m_e and m_c):
print("未能从文件中读取 n/e/c,请确认输出格式与样例一致。")
raise SystemExit(1)

n = int(m_n.group(1))
e = int(m_e.group(1))
c = int(m_c.group(1))
print("Loaded n,e,c")

hint_tuples = re.findall(r"Hint\s*\d+:\s*(\d+),\s*(\d+),\s*([0-9]+)", txt)
hints = [(int(a), int(b), int(val)) for (a,b,val) in hint_tuples]
print("Loaded", len(hints), "hints")

from collections import defaultdict
groups1 = defaultdict(list)
groups2 = defaultdict(list)
for idx, (a,b,val) in enumerate(hints, start=1):
groups1[a].append((idx,a,b,val))
groups2[b].append((idx,a,b,val))

def try_pairs(pairs):
results = []
for i in range(len(pairs)):
for j in range(i+1, len(pairs)):
idx1,a1,b1,H1 = pairs[i]
idx2,a2,b2,H2 = pairs[j]
delta = (H1 - H2) % n
g = gcd(delta, n)
if 1 < g < n:
results.append((idx1, a1,b1, idx2, a2,b2, g))
return results

found = []
for a, items in groups1.items():
if len(items) >= 2:
res = try_pairs(items)
if res:
found.extend(res)

if found:
print("Found factor(s) by matching same base1:")
for it in found:
print(it)
else:
print("No factor found by matching same base1. Trying same base2...")
found2 = []
for b, items in groups2.items():
if len(items) >= 2:
res = try_pairs(items)
if res:
found2.extend(res)
if found2:
print("Found factor(s) by matching same base2:")
for it in found2:
print(it)
found = found2

if not found:
print("No factor found by same-base heuristics. Scanning all pairs (this may take some seconds)...")
all_pairs = []
for i in range(len(hints)):
for j in range(i+1, len(hints)):
a1,b1,H1 = hints[i]
a2,b2,H2 = hints[j]
delta = (H1 - H2) % n
g = gcd(delta, n)
if 1 < g < n:
all_pairs.append((i+1,a1,b1,j+1,a2,b2,g))
if all_pairs:
print("Found by scanning all pairs:")
for it in all_pairs:
print(it)
found = all_pairs
else:
print("每个 base1 的 hint 数量:")
for a, items in sorted(groups1.items()):
print("base1 =", a, "count =", len(items))
raise SystemExit(2)

g = found[0][-1]
p = int(g)
if n % p != 0:
print("警告: gcd 没能整除n:", p)
raise SystemExit(3)

q = n // p
print("\nRecovered p =", p)
print("Recovered q =", q)

phi = (p-1)*(q-1)
d = inverse(e, phi)
m = pow(c, d, n)
try:
flag = long_to_bytes(m)
print("\nflag (bytes):", flag)
try:
print("flag (utf-8):", flag.decode())
except:
pass
except Exception as exc:
print("转换为 bytes 失败,m 的值:", m)
raise

# flag: ISCTF{M0dIFi3D_f3RM47_7H30r3m_I5_fUn_8U7_h4rD3r!}
⬆︎TOP